package com.vtuzx.kingdee.xqc_api.service.impl;


import com.mongodb.client.result.DeleteResult;
import com.mongodb.client.result.UpdateResult;
import com.vtuzx.core.VtuzxException;
import com.vtuzx.core.bean.dto.VtuzxMap;
import com.vtuzx.core.bean.dto.VtuzxPage;
import com.vtuzx.core.bean.dto.VtuzxToken;
import com.vtuzx.core.constant.IVtuzxConst;
import com.vtuzx.core.file.excel.VtuzxExcel;
import com.vtuzx.core.file.excel.VtuzxExcelCell;
import com.vtuzx.core.file.excel.VtuzxExcelRow;
import com.vtuzx.core.file.excel.VtuzxExcelSheet;
import com.vtuzx.core.utils.VtuzxUtil;
import com.vtuzx.fast.utils.FastUtil;
import com.vtuzx.kingdee.xqc_api.service.IXqcInventoryService;
import com.vtuzx.kingdee.xqc_api.service.IXqcPurOrderService;
import com.vtuzx.kingdee.xqc_api.service.IXqcPurPackageService;
import com.vtuzx.kingdee.xqc_core.bean.VtuzxArrayList;
import com.vtuzx.kingdee.xqc_core.bean.xqc.BillMaterial;
import com.vtuzx.kingdee.xqc_core.bean.xqc.BillMaterialBox;
import com.vtuzx.kingdee.xqc_core.constant.*;
import com.vtuzx.kingdee.xqc_core.dao.*;
import com.vtuzx.web.bean.VtuzxDownloadBean;
import org.bson.Document;
import org.bson.types.ObjectId;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.stereotype.Service;

import java.io.ByteArrayOutputStream;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.SimpleDateFormat;
import java.util.*;


/**
 * 采购订单
 */
@Service
public class XqcPurPackageServiceImpl implements IXqcPurPackageService {

    /**
     * Logger
     */
    private static final Logger _logger = LoggerFactory.getLogger(XqcPurPackageServiceImpl.class);

    @Autowired
    private PurOrderDao purOrderDao;

    @Autowired
    private PurOrderDetailDao purOrderDetailDao;
//
//    @Autowired
//    private PurSettlementDao purSettlementDao;

    @Autowired
    private SupplierDao supplierDao;

//    @Autowired
//    private PurInSettlementDao purInSettlementDao;

//    @Autowired
//    private PurInSettlementDetailDao purInSettlementDetailDao;

//    @Autowired
//    private PurInSettlementBoxDao purInSettlementBoxDao;

    @Autowired
    private IXqcInventoryService inventoryService;

    @Autowired
    private PurContractDetailDao purContractDetailDao;

    @Autowired
    private PurInDao purInDao;

    @Autowired
    private PurInDetailDao purInDetailDao;

    @Autowired
    private PurInDetailBoxDao purInDetailBoxDao;

    @Override
    public VtuzxMap getPurOrderBill() {
        List<VtuzxMap> dataList = new ArrayList<>();
        Criteria cond = new Criteria("status").is("audit");
        cond.and("allIn").ne(true);
        Iterator<Document> purOrderItr = purOrderDao.findList(cond, null, 0, 0);
        while (purOrderItr.hasNext()) {
            Document purOrderDoc = purOrderItr.next();
            VtuzxMap dataMap = new VtuzxMap();
            String supplierNo = VtuzxUtil.getString(purOrderDoc, "supplierNo");
            Document supplierDoc = supplierDao.findOne(Criteria.where("fNumber").is(supplierNo));
            String supplierName = VtuzxUtil.getString(supplierDoc, "fName");
            dataMap.append("supplierName", supplierName);
            dataMap.append("billNo", VtuzxUtil.getString(purOrderDoc, "billNo"));
            dataMap.append("billDate", VtuzxUtil.getString(purOrderDoc, "billDate"));
            dataMap.append("orderNo", VtuzxUtil.getString(purOrderDoc, "orderNo"));
            dataMap.append("orderType", VtuzxUtil.getString(purOrderDoc, "orderType"));
            dataMap.append("purchaseDate", VtuzxUtil.getString(purOrderDoc, "purchaseDate"));
            dataMap.append("purchaseDept", VtuzxUtil.getString(purOrderDoc, "purchaseDept"));
            dataMap.append("purchaseDeptName", VtuzxUtil.getString(purOrderDoc, "purchaseDeptName"));
            dataMap.append("purchaser", VtuzxUtil.getString(purOrderDoc, "purchaser"));
            dataMap.append("purchaserName", VtuzxUtil.getString(purOrderDoc, "purchaserName"));
            dataMap.append("remark", VtuzxUtil.getString(purOrderDoc, "remark"));
            dataMap.append("charge", VtuzxUtil.getString(purOrderDoc, "charge"));
            dataMap.append("contractNo", VtuzxUtil.getString(purOrderDoc, "contractNo"));
            dataMap.append("settle", VtuzxUtil.getString(purOrderDoc, "settle"));
            dataMap.append("startDate", VtuzxUtil.getString(purOrderDoc, "startDate"));
            dataMap.append("endDate", VtuzxUtil.getString(purOrderDoc, "endDate"));
            dataMap.append("status", VtuzxUtil.getString(purOrderDoc, "status"));
            dataMap.append("supplierName", VtuzxUtil.getString(purOrderDoc, "supplierName"));
            dataMap.append("supplierNo", VtuzxUtil.getString(purOrderDoc, "supplierNo"));
            dataMap.append("_id", VtuzxUtil.getString(purOrderDoc, "_id"));
            dataList.add(dataMap);
        }

//        List<VtuzxMap> resList = new ArrayList<>();
//
//        for (VtuzxMap data: dataList) {
//            boolean noScan = false;
//            String orderNo = VtuzxUtil.getString(data, "orderNo");
//            Iterator<Document> purOrderDetailItr = purOrderDetailDao.findList(Criteria.where("orderNo").is(orderNo), null, 0, 0);
//            while (purOrderDetailItr.hasNext()) {
//                Document purOrderDetailDoc = purOrderDetailItr.next();
//                double unSettlementQty = VtuzxUtil.getDouble(purOrderDetailDoc, "unSettlementQty");
//                if (unSettlementQty > 0) {
//                    noScan = true;
//                }
//            }
//            if (noScan) {
//                resList.add(data);
//            }
//        }
        return new VtuzxMap("dataList", dataList);
    }

    @Override
    public VtuzxMap getPurOrderBillDetail(String orderNo) {
        List<VtuzxMap> dataList = new ArrayList<>();
        Criteria cond = new Criteria("orderNo").is(orderNo);
        Iterator<Document> purOrderDetailItr = purOrderDetailDao.findList(cond, null, 0, 0);
        while (purOrderDetailItr.hasNext()) {
            Document purOrderDetailDoc = purOrderDetailItr.next();
            VtuzxMap dataMap = new VtuzxMap();
            dataMap.append("id", VtuzxUtil.getString(purOrderDetailDoc, IVtuzxConst.Key__id));
            dataMap.append("billDetailId", VtuzxUtil.getString(purOrderDetailDoc, "_billDetailId"));
            dataMap.append("materialNo", VtuzxUtil.getString(purOrderDetailDoc, "materialNo"));
            dataMap.append("materialName", VtuzxUtil.getString(purOrderDetailDoc, "materialName"));
            dataMap.append("materialSpec", VtuzxUtil.getString(purOrderDetailDoc, "materialSpec"));
            dataMap.append("purchaseUnitName", VtuzxUtil.getString(purOrderDetailDoc, "purchaseUnitName"));
            dataMap.append("calcUnitName", VtuzxUtil.getString(purOrderDetailDoc, "calcUnitName"));
            dataMap.append("qty", VtuzxUtil.getInt(purOrderDetailDoc, "qty"));
            dataMap.append("unSettlementQty", VtuzxUtil.getInt(purOrderDetailDoc, "unSettlementQty"));
            dataList.add(dataMap);
        }
        return new VtuzxMap("dataList", dataList);
    }

    @Override
    public void createPurInSettlementBill(ObjectId userId, String userName, Map<String, Object> param) throws VtuzxException {
        String billNo = IXqcConst.createBillNo(BillType.CGRK);
        String htBillNo = VtuzxUtil.getString(param, "billNo");
        String orderNo = VtuzxUtil.getString(param, "orderNo");
        String supplierNo = VtuzxUtil.getString(param, "supplierNo");
        String supplierName = VtuzxUtil.getString(param, "supplierName");
        String stockNo = VtuzxUtil.getString(param, "stockNo");
        String locationNo = VtuzxUtil.getString(param, "locationNo");
        List<Map<String, Object>> dataList = VtuzxUtil.getObject(param, "dataList");
        List<Document> docList = new ArrayList<>();

        double sumCount = 0d;
        int boxCount = 0;
        for (Map<String, Object> data: dataList) {

            String materialNo = VtuzxUtil.getString(data, "materialNo");
            String materialName = VtuzxUtil.getString(data, "materialName");
            String materialSpec = VtuzxUtil.getString(data, "materialSpec");
            String batchNo = VtuzxUtil.getString(data, "batchNo");
            String unit = VtuzxUtil.getString(data, "unit");
            String billId = VtuzxUtil.getString(data, "id");
            int count = VtuzxUtil.getInt(data, "count");
            sumCount += count;
            boxCount++;
            System.out.println(boxCount);
            Document updateVal = new Document();

            updateVal.append("stockNo", stockNo);
            updateVal.append("billNo", billNo);
            updateVal.append("locationNo", locationNo);
            updateVal.append("materialNo", materialNo);
            updateVal.append("materialName", materialName);
            updateVal.append("materialSpec", materialSpec);
            updateVal.append("batchNo", batchNo);
            updateVal.append("unit", unit);
            updateVal.append("_createUserId", userId);
            updateVal.append("createUserName", userName);
            updateVal.append("count", count);
            updateVal.append("_detailId", FastUtil.convertId(billId));
            updateVal.append("settlementStatus", BillStatus.Save.toString());

            purOrderDetailDao.updateById(billId, new Document("scanCount", count));

            docList.add(updateVal);


        }

        purInDetailDao.insertMany(docList);

        Document dataDoc = new Document("billNo", billNo)
                .append("htBillNo", htBillNo)
                .append("orderNo", orderNo)
                .append("createType", PurInCreateType.Contact.toString())
                .append("supplierNo", supplierNo)
                .append("supplierName", supplierName)
                .append("stockNo", stockNo)
                .append("count", sumCount)
                .append("boxCount", boxCount)
                .append("status", BillStatus.Save.toString());

        purInDao.insertBill(userId, userName, dataDoc);

        auditPurOrderBill(userId, userName, billNo);
        // 数量反写
        for (Document doc: docList) {
            resetSettlementQty(doc);
        }

    }

    @Override
    public void auditPurOrderBill(ObjectId userId, String userName, String billNo) throws VtuzxException {
        List<BillMaterial> purOrderDetailList = new ArrayList<>();
        Document purOder = purInDao.findOne(Criteria.where("billNo").is(billNo));
        String supplierNo = VtuzxUtil.getString(purOder, "supplierNo");
        Iterator<Document> purOrderDetailItr = purInDetailDao.findList(Criteria.where("billNo").is(billNo), null, 0, 0);

        while (purOrderDetailItr.hasNext()) {
            Document purOrderDetailDoc = purOrderDetailItr.next();
            BillMaterial billMaterial = new BillMaterial();
            billMaterial.setMaterialNo(VtuzxUtil.getString(purOrderDetailDoc, "materialNo"));
            billMaterial.setUnit(VtuzxUtil.getString(purOrderDetailDoc, "unit"));
//            billMaterial.setBatchNo("");
//            billMaterial.setProduceDate("");
//            billMaterial.setExp();
            billMaterial.setStockNo(VtuzxUtil.getString(purOrderDetailDoc, "stockNo"));
            List<BillMaterialBox> boxList = new ArrayList<>();
            BillMaterialBox box = new BillMaterialBox();
            String materialNo = billMaterial.getMaterialNo();
            String boxNo = supplierNo + "|;" + materialNo + "|;" + "batch";
            box.setBoxNo(boxNo);
//            box.setRfid(VtuzxUtil.getString(purOrderDetailDoc, "rfid"));
            double count = VtuzxUtil.getDouble(purOrderDetailDoc, "count");
            box.setCount(count);
            box.setLocationNo(VtuzxUtil.getString(purOrderDetailDoc, "locationNo"));
            boxList.add(box);

            billMaterial.setBoxList(boxList);
            purOrderDetailList.add(billMaterial);
            purInDetailBoxDao.insertOne(new Document("_detailId", VtuzxUtil.getObject(purOrderDetailDoc, IVtuzxConst.Key__id))
                    .append("boxNo", boxNo)
                    .append("count", count)
                    .append("unit", VtuzxUtil.getString(purOrderDetailDoc, "unit"))
                    .append("stockNo", VtuzxUtil.getString(purOrderDetailDoc, "stockNo"))
                    .append("locationNo", VtuzxUtil.getString(purOrderDetailDoc, "locationNo")));
        }
        purInDao.audit(userId, userName, billNo);
        try {
            inventoryService.addInventory(userId, userName, BillEvent.Audit, BillType.CGRK, billNo, purOrderDetailList);

        } catch(Exception e) {
            purInDao.updateOne(Criteria.where("orderNo").is(billNo), new Document("status", BillStatus.Save.toString()));
            throw e;
        }

    }

    @Override
    public VtuzxMap updatePurOrderCount(ObjectId userId, String userName, String id, int count) {
        purOrderDetailDao.updateById(id, new Document("scanSettlementQty", count).append("noSaveStatus", true));
        return new VtuzxMap("res", true);
    }

    @Override
    public VtuzxMap getPurInSettlementList(ObjectId userId, Map<String, Object> param, String userName) {
        String billNo = VtuzxUtil.getString(param, "billNo");
        String htBillNo = VtuzxUtil.getString(param, "htBillNo");
        String orderNo = VtuzxUtil.getString(param, "orderNo");
        String stockNo = VtuzxUtil.getString(param, "stockNo");
        String name = VtuzxUtil.getString(param, "createUserName");
        int pageIndex = VtuzxUtil.getInt(param, "pageIndex");
        int pageSize = VtuzxUtil.getInt(param, "pageSize");
        List<String> createTime = VtuzxUtil.getObject(param, "createTime");
        Criteria cond = Criteria.where("createType").is(PurInCreateType.Contact.toString());
        if (!VtuzxUtil.isEmpty(htBillNo)) {
            cond.and("htBillNo").regex(htBillNo);
        }
        if (!VtuzxUtil.isEmpty(billNo)) {
            cond.and("billNo").regex(billNo);
        }
        if (!VtuzxUtil.isEmpty(orderNo)) {
            cond.and("orderNo").regex(orderNo);
        }
        if (!VtuzxUtil.isEmpty(stockNo)) {
            cond.and("stockNo").regex(stockNo);
        }
        if (!VtuzxUtil.isEmpty(name)) {
            cond.and("createUserName").regex(name);
        }
        if (!VtuzxUtil.isEmpty(createTime)) {
            cond.and("createTime").gte(VtuzxUtil.parseDate(createTime.get(0))).lte(VtuzxUtil.parseDate(createTime.get(1) + " 23:59:59"));
        }
        VtuzxPage page = purInDao.page(cond, new Document("createTime", -1), pageIndex, pageSize);
        List<VtuzxMap> dataList = page.iterator(doc -> new VtuzxMap("id", VtuzxUtil.getString(doc, IVtuzxConst.Key__id))
                .append("billNo", VtuzxUtil.getString(doc, "billNo"))
                .append("htBillNo", VtuzxUtil.getString(doc, "htBillNo"))
                .append("orderNo", VtuzxUtil.getString(doc, "orderNo"))
                .append("stockNo", VtuzxUtil.getString(doc, "stockNo"))
                .append("count", VtuzxUtil.getDouble(doc, "count"))
                .append("supplierNo", VtuzxUtil.getString(doc, "supplierNo"))
                .append("supplierName", VtuzxUtil.getString(doc, "supplierName"))
                .append("createUserName", VtuzxUtil.getString(doc, "createUserName"))
                .append("createTime", VtuzxUtil.formatYmdHmsF(VtuzxUtil.getObject(doc, "createTime")))
        );
        return new VtuzxMap(IVtuzxConst.Key_total, page.total()).append(IVtuzxConst.Key_data, dataList);
    }

    @Override
    public VtuzxMap getPurInSettlementDetail(ObjectId userId, Map<String, Object> param, String userName) {
        List<VtuzxMap> dataList = new ArrayList<>();
        String billNo = VtuzxUtil.getString(param, "billNo");
        Document purInSettlementDoc = purInDao.findOne(Criteria.where("billNo").is(billNo));
        VtuzxMap header = new VtuzxMap(purInSettlementDoc);
        header.append("id", VtuzxUtil.removeString(header, "_id"));
        header.append("createUserId", VtuzxUtil.removeString(header, "_createUserId"));
        header.append("auditUserId", VtuzxUtil.removeString(header, "_auditUserId"));
        String createTime = VtuzxUtil.formatYmdHmsF(VtuzxUtil.getObject(header, "createTime"));
        header.remove("createTime");
        header.append("createTime", createTime);

        Iterator<Document> purInSettlementDetail = purInDetailDao.findList(Criteria.where("billNo").is(billNo), null, 0,0);
        while (purInSettlementDetail.hasNext()) {
            Document detailDoc = purInSettlementDetail.next();
            VtuzxMap detailMap = new VtuzxMap(detailDoc);

            detailMap.append("id", VtuzxUtil.removeString(detailMap, "_id"));
            detailMap.append("createUserId", VtuzxUtil.removeString(detailMap, "_createUserId"));
            String time = VtuzxUtil.formatYmdHmsF(VtuzxUtil.getObject(detailMap, "createTime"));
            detailMap.remove("createTime");
            detailMap.append("createTime", time);
            dataList.add(detailMap);
        }

        return new VtuzxMap("header", header).append(IVtuzxConst.Key_data, dataList);
    }

    @Override
    public void settlementMaterial(ObjectId userId, Map<String, Object> param, String userName) throws VtuzxException {
        String id = VtuzxUtil.getString(param, "id");
        double settlementAmount = VtuzxUtil.getDouble(param, "amount");
        Document settleDetailDoc = purInDetailDao.findById(id);
        if (settleDetailDoc == null) {
            throw new VtuzxException(IVtuzxConst.Msg_E_target_not_exist);
        }
        purInDetailDao.updateById(id, new Document("settlementAmount", settlementAmount).append("settlementStatus", BillStatus.Audit.toString()));
        resetSettlementAmount(settleDetailDoc);
    }

    @Override
    public void unSettlementMaterial(ObjectId userId, Map<String, Object> param, String userName) throws VtuzxException {
        String id = VtuzxUtil.getString(param, "id");
        Document settleDetailDoc = purInDetailDao.findById(id);
        if (settleDetailDoc == null) {
            throw new VtuzxException(IVtuzxConst.Msg_E_target_not_exist);
        }
        purInDetailDao.updateById(id, new Document("settlementStatus", BillStatus.Save.toString()));
        resetSettlementAmount(settleDetailDoc);
    }

    private void resetSettlementAmount(Document settleDetailDoc) {
        ObjectId _detailId = VtuzxUtil.getObject(settleDetailDoc, "_detailId");
        Document detail = purOrderDetailDao.findById(_detailId);
        {
            // 订单分录结算信息重新计算
            Criteria cond = Criteria.where("_detailId").is(_detailId).and("settlementStatus").is(BillStatus.Audit.toString());
            Iterator<Document> itr = purInDetailDao.findList(cond, null, 0, 0);
            int count = 0;
//            int qty = 0;
            double amount = 0d;
            while(itr.hasNext()) {
                Document doc = itr.next();
                count++;
//                qty += VtuzxUtil.getInt(doc, "count");
                amount += VtuzxUtil.getDouble(doc, "settlementAmount");
            }
//            int totalQty = VtuzxUtil.getInt(detail, "qty");
            purOrderDetailDao.updateById(_detailId,
                    new Document("settlementAmount", amount).append("settlementCount", count));
        }
        ObjectId _billDetailId = VtuzxUtil.getObject(detail, "_billDetailId");
        if (_billDetailId != null) {
            // 合同分录结算信息重新计算
            Criteria cond = Criteria.where("_billDetailId").is(_billDetailId);
            Iterator<Document> itr = purOrderDetailDao.findList(cond, null, 0, 0);
            int count = 0;
//            int qty = 0;
            double amount = 0d;
            while(itr.hasNext()) {
                Document doc = itr.next();
                count += VtuzxUtil.getDouble(doc, "settlementCount");
//                qty += VtuzxUtil.getDouble(doc, "settlementQty");
                amount += VtuzxUtil.getDouble(doc, "settlementAmount");
            }
            purContractDetailDao.updateById(_billDetailId,
                    new Document("settlementAmount", amount).append("settlementCount", count));
        }
    }

    private void resetSettlementQty(Document settleDetailDoc) {
        ObjectId _detailId = VtuzxUtil.getObject(settleDetailDoc, "_detailId");
        Document detail = purOrderDetailDao.findById(_detailId);
        String orderNo = VtuzxUtil.getString(detail, "orderNo");
        {
            // 订单分录结算信息重新计算
            Criteria cond = Criteria.where("_detailId").is(_detailId);
            Iterator<Document> itr = purInDetailDao.findList(cond, null, 0, 0);
            int qty = 0;
            while(itr.hasNext()) {
                Document doc = itr.next();
                qty += VtuzxUtil.getInt(doc, "count");
            }
            int totalQty = VtuzxUtil.getInt(detail, "qty");
            purOrderDetailDao.updateById(_detailId,
                    new Document("settlementQty", qty).append("unSettlementQty", totalQty - qty));
        }
        Iterator<Document> orderDetailItr = purOrderDetailDao.findList(Criteria.where("orderNo").is(orderNo), null, 0, 0);
        boolean allIn = false;
        while (orderDetailItr.hasNext()) {
            Document orderDoc = orderDetailItr.next();
            int qty = VtuzxUtil.getInt(orderDoc, "qty");
            int settlementQty = VtuzxUtil.getInt(orderDoc, "settlementQty");
            if (qty - settlementQty == 0) {
                allIn = true;
            }
        }
        purOrderDao.updateOne(Criteria.where("orderNo").is(orderNo), new Document("allIn", allIn));

        ObjectId _billDetailId = VtuzxUtil.getObject(detail, "_billDetailId");
        if (_billDetailId != null) {
            // 合同分录结算信息重新计算
            Criteria cond = Criteria.where("_billDetailId").is(_billDetailId);
            Iterator<Document> itr = purOrderDetailDao.findList(cond, null, 0, 0);
            int qty = 0;
            while(itr.hasNext()) {
                Document doc = itr.next();
                qty += VtuzxUtil.getInt(doc, "settlementQty");
            }
            purContractDetailDao.updateById(_billDetailId, new Document("settlementQty", qty));
        }
    }
}
